home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1983, 1988 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- #ifndef lint
- char copyright[] =
- "@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\
- All rights reserved.\n";
- #endif /* not lint */
-
- #ifndef lint
- static char sccsid[] = "@(#)rshd.c 5.17.1.2 (Berkeley) 2/7/89";
- #endif /* not lint */
-
- /*
- * remote shell server:
- * [port]\0
- * remuser\0
- * locuser\0
- * command\0
- * data
- */
- #ifdef __svr4__
- #include <unistd.h> /* for F_OK */
- /* XXX the next two should be keyed with their own #ifdef */
- #define killpg(p,s) kill(-(p),(s))
- #define setpgrp(x,y) setsid()
- #define BSD_COMP /* for sys/ioctl.h */
- #endif
-
- #ifdef USE_STRING_H
- #define index strchr
- #define rindex strrchr
- #define bcmp memcmp
- #else
- #include <strings.h>
- #endif
-
- #include <sys/param.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <sys/file.h>
- #include <sys/time.h>
-
- #include <netinet/in.h>
-
- #include <arpa/inet.h>
-
- #include <stdio.h>
- #include <errno.h>
- #include <pwd.h>
- #include <signal.h>
- #include <netdb.h>
- #include <syslog.h>
-
- int errno;
- int keepalive = 1;
- char *index(), *rindex(), *strncat();
- /*VARARGS1*/
- int error();
-
- #if defined(sun) || defined(ultrix)
- int _check_rhosts_file;
- #endif
-
- /* Ultrix syslog(3) has no facility or options */
- #ifndef LOG_DAEMON
- #define LOG_DAEMON 0
- #define LOG_ODELAY 0
- #endif
-
- char *procname;
-
- /*ARGSUSED*/
- main(argc, argv)
- int argc;
- char **argv;
- {
- extern int opterr, optind, _check_rhosts_file;
- struct linger linger;
- int ch, on = 1, fromlen;
- struct sockaddr_in from;
-
- umask(022);
-
- procname = argv[0];
-
- openlog(procname, LOG_PID | LOG_ODELAY, LOG_DAEMON);
-
- opterr = 0;
- while ((ch = getopt(argc, argv, "ln")) != EOF)
- switch((char)ch) {
- case 'l':
- _check_rhosts_file = 0;
- break;
- case 'n':
- keepalive = 0;
- break;
- case '?':
- default:
- syslog(LOG_ERR, "usage: rshd [-l]");
- break;
- }
-
- argc -= optind;
- argv += optind;
-
-
- fromlen = sizeof (from);
- if (getpeername(0, &from, &fromlen) < 0) {
- fprintf(stderr, "%s: ", argv[0]);
- perror("getpeername");
- _exit(1);
- }
- if (keepalive &&
- setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
- sizeof(on)) < 0)
- syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
- linger.l_onoff = 1;
- linger.l_linger = 60; /* XXX */
- if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
- sizeof (linger)) < 0)
- syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
- doit(&from);
- }
-
- char username[20] = "USER=";
- char homedir[64] = "HOME=";
- char shell[64] = "SHELL=";
- char *envinit[] =
- #ifdef __svr4__
- {homedir, shell, "PATH=/usr/bin:", username, 0};
- #else
- {homedir, shell, "PATH=/usr/ucb:/bin:/usr/bin:", username, 0};
- #endif
- char **environ;
-
- doit(fromp)
- struct sockaddr_in *fromp;
- {
- char cmdbuf[NCARGS+1], *cp;
- char locuser[16], remuser[16];
- struct passwd *pwd;
- int s;
- struct hostent *hp;
- char *hostname;
- short port;
- int pv[2], pid, cc;
- int nfd;
- fd_set ready, readfrom;
- char buf[BUFSIZ], sig;
- int one = 1;
- char remotehost[2 * MAXHOSTNAMELEN + 1];
-
- (void) signal(SIGINT, SIG_DFL);
- (void) signal(SIGQUIT, SIG_DFL);
- (void) signal(SIGTERM, SIG_DFL);
- #ifdef DEBUG
- { int t = open("/dev/tty", 2);
- if (t >= 0) {
- ioctl(t, TIOCNOTTY, (char *)0);
- (void) close(t);
- }
- }
- #endif
- fromp->sin_port = ntohs((u_short)fromp->sin_port);
- if (fromp->sin_family != AF_INET) {
- syslog(LOG_ERR, "malformed from address\n");
- exit(1);
- }
- #ifdef IP_OPTIONS
- {
- u_char optbuf[BUFSIZ/3], *cp;
- char lbuf[BUFSIZ], *lp;
- int optsize = sizeof(optbuf), ipproto;
- struct protoent *ip;
-
- if ((ip = getprotobyname("ip")) != NULL)
- ipproto = ip->p_proto;
- else
- ipproto = IPPROTO_IP;
- if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0 &&
- optsize != 0) {
- lp = lbuf;
- for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
- sprintf(lp, " %2.2x", *cp);
- syslog(LOG_NOTICE,
- "Connection received using IP options (ignored):%s", lbuf);
- if (setsockopt(0, ipproto, IP_OPTIONS,
- (char *)NULL, optsize) != 0) {
- syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
- exit(1);
- }
- }
- }
- #endif
-
- if (fromp->sin_port >= IPPORT_RESERVED ||
- fromp->sin_port < IPPORT_RESERVED/2) {
- syslog(LOG_NOTICE, "Connection from %s on illegal port",
- inet_ntoa(fromp->sin_addr));
- exit(1);
- }
-
- (void) alarm(60);
- port = 0;
- for (;;) {
- char c;
- if ((cc = read(0, &c, 1)) != 1) {
- if (cc < 0)
- syslog(LOG_NOTICE, "read: %m");
- shutdown(0, 1+1);
- exit(1);
- }
- if (c == 0)
- break;
- port = port * 10 + c - '0';
- }
-
- (void) alarm(0);
- if (port != 0) {
- int lport = IPPORT_RESERVED - 1;
- s = rresvport(&lport);
- if (s < 0) {
- syslog(LOG_ERR, "can't get stderr port: %m");
- exit(1);
- }
- if (port >= IPPORT_RESERVED) {
- syslog(LOG_ERR, "2nd port not reserved\n");
- exit(1);
- }
- fromp->sin_port = htons((u_short)port);
- if (connect(s, fromp, sizeof (*fromp)) < 0) {
- syslog(LOG_INFO, "connect second port: %m");
- exit(1);
- }
- }
-
- #ifdef ultrix /* inetd does not set up 1 and 2 */
- dup2(0, 1);
- dup2(0, 2);
- #endif
-
- #ifdef notdef
- /* from inetd, socket is already on 0, 1, 2 */
- dup2(f, 0);
- dup2(f, 1);
- dup2(f, 2);
- #endif
- hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
- fromp->sin_family);
- if (hp) {
- /*
- * If name returned by gethostbyaddr is in our domain,
- * attempt to verify that we haven't been fooled by someone
- * in a remote net; look up the name and check that this
- * address corresponds to the name.
- */
- #ifdef bug
- if (local_domain(hp->h_name)) {
- #endif
- strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
- remotehost[sizeof(remotehost) - 1] = 0;
- hp = gethostbyname(remotehost);
- if (hp == NULL) {
- syslog(LOG_INFO,
- "Couldn't look up address for %s",
- remotehost);
- error("Couldn't look up address for your host");
- exit(1);
- } else for (; ; hp->h_addr_list++) {
- if (!bcmp(hp->h_addr_list[0],
- (caddr_t)&fromp->sin_addr,
- sizeof(fromp->sin_addr)))
- break;
- if (hp->h_addr_list[0] == NULL) {
- syslog(LOG_NOTICE,
- "Host addr %s not listed for host %s",
- inet_ntoa(fromp->sin_addr),
- hp->h_name);
- error("Host address mismatch");
- exit(1);
- }
- }
- #ifdef bug
- }
- hostname = hp->h_name;
- #else
- hostname = remotehost;
- #endif
- } else
- hostname = inet_ntoa(fromp->sin_addr);
-
- getstr(remuser, sizeof(remuser), "remuser");
- getstr(locuser, sizeof(locuser), "locuser");
- getstr(cmdbuf, sizeof(cmdbuf), "command");
- do_access(procname, hostname, inet_ntoa(fromp->sin_addr),
- remuser, locuser);
- setpwent();
- pwd = getpwnam(locuser);
- if (pwd == NULL) {
- error("Login incorrect.\n");
- exit(1);
- }
- endpwent();
- if (chdir(pwd->pw_dir) < 0) {
- (void) chdir("/");
- #ifdef notdef
- error("No remote directory.\n");
- exit(1);
- #endif
- }
-
- if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
- ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
- error("Permission denied.\n");
- exit(1);
- }
-
- if (pwd->pw_uid && !access("/etc/nologin", F_OK)) {
- error("Logins currently disabled.\n");
- exit(1);
- }
- (void) write(2, "\0", 1);
-
- if (port) {
- if (pipe(pv) < 0) {
- error("Can't make pipe.\n");
- exit(1);
- }
- pid = fork();
- if (pid == -1) {
- error("Try again.\n");
- exit(1);
- }
- if (pv[0] > s)
- nfd = pv[0];
- else
- nfd = s;
- nfd++;
- if (pid) {
- (void) close(0); (void) close(1); (void) close(2);
- (void) close(pv[1]);
- FD_ZERO(&readfrom);
- FD_SET(s, &readfrom);
- FD_SET(pv[0], &readfrom);
- ioctl(pv[0], FIONBIO, (char *)&one);
- /* should set s nbio! */
- do {
- ready = readfrom;
- if (select(nfd, &ready, (fd_set *)0,
- (fd_set *)0, (struct timeval *)0) < 0)
- break;
- if (FD_ISSET(s, &ready)) {
- if (read(s, &sig, 1) <= 0)
- FD_CLR(s, &readfrom);
- else
- killpg(pid, sig);
- }
- if (FD_ISSET(pv[0], &ready)) {
- errno = 0;
- cc = read(pv[0], buf, sizeof (buf));
- if (cc <= 0) {
- shutdown(s, 1+1);
- FD_CLR(pv[0], &readfrom);
- } else
- (void) write(s, buf, cc);
- }
- } while (FD_ISSET(s, &readfrom) ||
- FD_ISSET(pv[0], &readfrom));
- exit(0);
- }
- setpgrp(0, getpid());
- (void) close(s); (void) close(pv[0]);
- dup2(pv[1], 2);
- }
- if (*pwd->pw_shell == '\0')
- pwd->pw_shell = "/bin/sh";
- (void) setgid((gid_t)pwd->pw_gid);
- initgroups(pwd->pw_name, pwd->pw_gid);
- (void) setuid((uid_t)pwd->pw_uid);
- environ = envinit;
- strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
- strncat(shell, pwd->pw_shell, sizeof(shell)-7);
- strncat(username, pwd->pw_name, sizeof(username)-6);
- cp = rindex(pwd->pw_shell, '/');
- if (cp)
- cp++;
- else
- cp = pwd->pw_shell;
- execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
- perror(pwd->pw_shell);
- exit(1);
- }
-
- /*VARARGS1*/
- error(fmt, a1, a2, a3)
- char *fmt;
- int a1, a2, a3;
- {
- char buf[BUFSIZ];
-
- buf[0] = 1;
- (void) sprintf(buf+1, fmt, a1, a2, a3);
- (void) write(2, buf, strlen(buf));
- }
-
- getstr(buf, cnt, err)
- char *buf;
- int cnt;
- char *err;
- {
- char c;
-
- do {
- if (read(0, &c, 1) != 1)
- exit(1);
- *buf++ = c;
- if (--cnt == 0) {
- error("%s too long\n", err);
- exit(1);
- }
- } while (c != 0);
- }
-
- /*
- * Check whether host h is in our local domain,
- * as determined by the part of the name following
- * the first '.' in its name and in ours.
- * If either name is unqualified (contains no '.'),
- * assume that the host is local, as it will be
- * interpreted as such.
- */
- local_domain(h)
- char *h;
- {
- char localhost[MAXHOSTNAMELEN];
- char *p1, *p2 = index(h, '.');
-
- (void) gethostname(localhost, sizeof(localhost));
- p1 = index(localhost, '.');
- if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
- return(1);
- return(0);
- }
-
- do_access(daemon, host, addr, ruser, luser)
- char *daemon;
- char *host;
- char *addr;
- char *ruser;
- char *luser;
- {
- int allow = hosts_ctl(daemon, strcmp(host, addr) ? host : "unknown",
- addr, ruser);
- char *text = allow ? "" : "refused ";
-
- if (strcmp(ruser, luser) == 0)
- syslog(LOG_INFO, "%sconnect from %s@%s",
- text, ruser, host);
- else
- syslog(LOG_INFO, "%sconnect from %s@%s to %s",
- text, ruser, host, luser);
- if (!allow)
- exit(0);
- }
-